package io.gitee.dtdage.app.boot.starter.common.context;

import io.gitee.dtdage.app.boot.starter.common.BaseBean;
import lombok.SneakyThrows;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Bean工厂
 *
 * @author WFT
 * @since 2024/4/14
 */
public abstract class BeanFactory<K extends Serializable, B extends BaseBean<K>> implements ApplicationContextAware {

    private Map<K, B> map = null;
    private Class<B> clazz;
    private ApplicationContext context;

    @Override
    @SneakyThrows
    public void setApplicationContext(ApplicationContext context) {
        //  获取泛型超类
        Type superclass = this.getClass().getGenericSuperclass();
        if (superclass instanceof ParameterizedType) {
            //  获取泛型的类型列表
            Type[] arguments = ((ParameterizedType) superclass).getActualTypeArguments();
            //  获取Bean的完整名称
            String className = arguments[arguments.length - 1].toString()
                    //  去除不必要的字符
                    .replaceAll("^class", "")
                    .replaceAll("^interface", "")
                    .replaceAll("<.*>$", "")
                    .trim();
            //  noinspection unchecked
            this.clazz = (Class<B>) Class.forName(className);
        }
        this.context = context;
    }

    /**
     * 获取实例对象
     *
     * @param key 主键
     * @return {@link BaseBean}
     */
    public B getInstance(K key) {
        return this.getOptional(key).orElseThrow(this::illegalArgumentException);
    }

    public Optional<B> getOptional(K key) {
        return Optional.ofNullable(this.getBeanMap().get(key));
    }

    private Map<K, B> getBeanMap() {
        this.map = Optional.ofNullable(this.map).orElseGet(() -> {
            Collection<B> list = this.context.getBeansOfType(this.clazz).values();
            return list.stream().collect(Collectors.toMap(B::getId, bean -> bean));
        });
        return this.map;
    }

    /**
     * 构建一个非法参数异常
     * 当无法通过调用者传入的参数从map中获取到实例时,将抛出此异常
     *
     * @return {@link IllegalArgumentException}
     */
    protected IllegalArgumentException illegalArgumentException() {
        return new IllegalArgumentException("This class does not exist!");
    }

}
